﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace UlsStudio.Engine
{
    #region AbstractLoadingStatus

    /// <summary>
    /// A load status for a file-load or real-time job
    /// </summary>
    public abstract class AbstractLoadingStatus
    {
        #region Constructors & Privates

        public AbstractLoadingStatus(ScanSettings settings)
        {
            this._settings = settings;
            this.LoadStartTime = DateTime.Now;
        }
        private readonly ScanSettings _settings = null;

        #endregion

        /// <summary>
        /// When the load started
        /// </summary>
        public DateTime LoadStartTime { get; set; }

        /// <summary>
        /// Percentage done
        /// </summary>
        public abstract int PercentageComplete { get;  }

        /// <summary>
        /// Returns if the load is complete (progress == 100%)
        /// </summary>
        public bool LoadComplete { get { return this.PercentageComplete == 100; } }

        /// <summary>
        /// Settings used for the load
        /// </summary>
        public ScanSettings Settings { get { return _settings; } }
    }

    #endregion

    #region RealTimeLoadingStatus

    public class RealTimeLoadingStatus : AbstractLoadingStatus
    {

        /// <summary>
        /// Realtime statuses are always 100% done when you receive them
        /// </summary>
        public override int PercentageComplete  { get { return 100; }  }

        public int RowsInserted { get; set; }

        public RealTimeLoadingStatus() : this(new RealTimeScanSettings()) { }
        public RealTimeLoadingStatus(ScanSettings settings, int rowsInserted) : base(settings) 
        {
            this.RowsInserted = rowsInserted;
        }

        public RealTimeLoadingStatus(ScanSettings settings) : base(settings) { }
    }

    #endregion

    #region FileSetLoadCompleteStatus

    /// <summary>
    /// Represents job done loading files
    /// </summary>
    public class FileSetLoadCompleteStatus : AbstractLoadingStatus
    {
        public FileSetLoadCompleteStatus(UlsScanSettings settings)
            : base(settings)
        {
        }

        public override int PercentageComplete
        {
            get { return 100; }
        }
    }

    #endregion

    #region FileSetJobLoadingStatus

    /// <summary>
    /// Current loading job status for files being loaded
    /// </summary>
    public class FileSetJobLoadingStatus : AbstractLoadingStatus
    {
        #region Privates & Constructors

        static object lineParsingThreadListLockObj = new object();
        private Dictionary<Guid, FileParserThreadStage> _threadList = null;
        private bool _userClickedCancel = false;
        object userClickedCancelLockObj = new object();
        private readonly long _bytesTotal = 0;

        public FileSetJobLoadingStatus(UlsScanSettings settings) : base(settings)
        {
            _threadList = new Dictionary<Guid, FileParserThreadStage>();
            bytesLoadedTable = new Dictionary<string, long>();

            // Calculate total bytes to load
            foreach (FileInfo fileToLoad in settings.FilesToBeScanned)
            {
                _bytesTotal += fileToLoad.Length;
            }
        }
        public FileSetJobLoadingStatus() : this(new UlsScanSettings(new List<System.IO.FileInfo>())) { }
        #endregion

        #region Properties

        /// <summary>
        /// Currently loading filename
        /// </summary>
        public System.IO.FileInfo CurrentFile { get; set; }

        /// <summary>
        /// Total file data (set in constructor)
        /// </summary>
        public long BytesTotal { get { return _bytesTotal; } }

        /// <summary>
        /// Has the user clicked cancel
        /// </summary>
        public bool UserCancelledLoad
        {
            get
            {
                lock (userClickedCancelLockObj) { return _userClickedCancel; }
            }
            set
            {
                lock (userClickedCancelLockObj) { _userClickedCancel = value; }
            }
        }

        /// <summary>
        /// Bytes processed thus far
        /// </summary>
        public long BytesProcessed
        {
            get
            {
                long totalFileBytesLoaded = 0;
                foreach (long fileBytesLoaded in bytesLoadedTable.Values)
                {
                    totalFileBytesLoaded += fileBytesLoaded;
                }
                if (lastTotal != 0 && lastTotal > totalFileBytesLoaded)
                {
                    Logging.Writeline("eh?");
                }
                lastTotal = totalFileBytesLoaded;
                return totalFileBytesLoaded;

            }
        }
        private long lastTotal = 0;

        /// <summary>
        /// Loader threads still running
        /// </summary>
        internal int LoaderThreadCount
        {
            get { return LineParsingThreadList.Count; }
        }

        /// <summary>
        /// Loader thread info
        /// </summary>
        internal Dictionary<Guid, FileParserThreadStage> LineParsingThreadList
        {
            get { lock (lineParsingThreadListLockObj) return _threadList; }
        }

        /// <summary>
        /// Percentage of data loaded
        /// </summary>
        public override int PercentageComplete
        {
            get
            {
                int percentageDone = 0;
                if (this.BytesTotal > 0)
                {
                    double d = (Convert.ToDouble(this.BytesProcessed) / Convert.ToDouble(this.BytesTotal)) * 100;
                    percentageDone = Convert.ToInt32(Math.Round(d, 0));
                }
                else
                {
                    percentageDone = 100;
                }

                // By definition, if this status is "files loading" we can't be at 100% - threads will still be inserting SQL data
                // ...despite all files being read.
                // A FileSetLoadCompleteStatus object is used to represent 100% done
                if (percentageDone == 100)
                {
                    percentageDone = 99;
                }
                
                return percentageDone;
            }
        }

        #endregion

        private Dictionary<string, long> bytesLoadedTable = null;

        /// <summary>
        /// Set a file bytes parsed value in the set of files to load.
        /// </summary>
        public void SetFileLoadingProgress(string fileBeingLoaded, long bytesLoaded)
        {
            if (bytesLoadedTable.ContainsKey(fileBeingLoaded))
            {
                bytesLoadedTable[fileBeingLoaded] = bytesLoaded;
                //Logging.Writeline("CurrentLoadJobLoadStatus.SetFileLoadingStatus - Setting bytes as {0} for {1}", bytesLoaded, fileBeingLoaded);
            }
            else
            {
                bytesLoadedTable.Add(fileBeingLoaded, bytesLoaded);
                //Logging.Writeline("CurrentLoadJobLoadStatus.SetFileLoadingStatus - ADDING bytes as {0} for {1}", bytesLoaded, fileBeingLoaded);
            }
        }

    }

    #endregion

    #region AwaitingDataLoadingStatus

    public class AwaitingDataLoadingStatus : AbstractLoadingStatus
    {
        public AwaitingDataLoadingStatus() : base(new RealTimeScanSettings()) { }
        public override int PercentageComplete
        {
            get { return 0; }
        }
    }

    #endregion
}
